/*
 * =====================================================================================
 *       Filename:  pool.c
 *    Description:  请求客户端请求的线程池
 *        Created:  2015-07-07 10:00
 *         Author:  mien, m@p58.net
 * =====================================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>
#include "config.h"
#include "net.h"
#include "pool.h"
#include "http/http.h"

clientRequestTask* task = NULL;
time_t poolCleanTimePoint = 0;
static void* poolRoutine(void *arg);

static clientRequestTask* createTask(int fd)
{
    clientRequestTask *t = (clientRequestTask*) calloc(1, sizeof(clientRequestTask));
    t->fd = fd;
    t->lwritten = 1;
    sem_init(&(t->sem), 0, 0);
    pthread_create(&(t->thread_id), NULL, poolRoutine, t);
    return t;
}

void poolInit()
{
    int i;
    for (i = 0; i < SPARE_THREADS_NUM; i++) {
        clientRequestTask *t = createTask(0);
        if (task == NULL) {
            task = t;
        }
        else {
            t->next = task;
            task = t;
        }
    }
}

static void poolClean()
{
    /* 每天清理一次空闲线程 */
    if (time(NULL) - poolCleanTimePoint < 86400)
        return; 

    time(&poolCleanTimePoint);
    
    /* 当前空闲线程数目 */
    int n = 0;
    clientRequestTask *t = task;
    while (t != NULL) {
        if (t->fd == 0)
            n++;
        t = t->next;
    }

    if (n <= SPARE_THREADS_NUM)
        return;

    /* 清理超过预定数目的空闲线程 */
    int i = 0;
    clientRequestTask *prev = NULL, *cur = NULL;
    n -= SPARE_THREADS_NUM;
    t = task;
    while (t != NULL) {
        if (t->fd == 0) {
            cur = t;
            t = t->next;
            if (prev == NULL)
                task = t;
            else
                prev->next = t;

            cur->exit = 1;
            sem_post(&(cur->sem));
            pthread_join(cur->thread_id, NULL);
            free(cur);

            i++;
            if (i >= n)
                break;
        }
        else {
            prev = t;
            t = t->next;
        }
    }
}

void poolHandle(int fd)
{
    clientRequestTask *worker = NULL, *t = task;

    /* 清理线程 */
    poolClean();

    /* 查找对应的工作线程 */
    while (t != NULL) {
        /* 查找对应的工作任务 */
        if (t->fd == fd) {
            worker = t;
            break;
        }
        /* 没有对应的工作任务，选择一个空闲的 */
        if (worker == NULL && t->fd == 0)
            worker = t;
        t = t->next;
    }

    /* 无对应和空闲，新建立一个 */
    if (worker == NULL) {
        worker = createTask(fd);
        worker->next = task;
        task = worker;
    }
    if (worker->fd != fd)
        worker->fd = fd;

    /* 唤醒线程 */
    sem_post(&(worker->sem));
}

int poolDestroy()
{
    clientRequestTask* head = NULL;
    while (task != NULL) {
        head = task;
        task = task->next;
        head->exit = 1;
        sem_post(&(head->sem));
        pthread_join(head->thread_id, NULL);
        free(head);
    }

    return 0;
}

static void* poolRoutine(void *arg)
{
    clientRequestTask* t = (clientRequestTask*) arg;

    while (1) { // loop for next client sock
        if (t->exit == 0)
            sem_wait(&(t->sem));

        if (t->exit == 1) {
            sem_destroy(&(t->sem));
            pthread_exit(NULL);
        }
        
        httpHandle(t);
        t->lwritten = 1;
        t->fd = 0; // 处理完此次请求后，线程改为空闲状态
    }
}

